#include "mysql.h"

//PathInfo 相关函数，二次生成各种切割出路径
//1.获取父目录的单一路径名
void getParentPath(const char *filepath, char *parentpath){
    strncpy(parentpath,filepath,1024);
    char *lastslash = strrchr(parentpath,'/');  //反向切割，找到倒数/分割的倒数第二个参数
    if (lastslash != NULL && lastslash != parentpath){
        *lastslash = '\0';   //截断，并获取父目录路径
    } else {
        strcpy(parentpath, "/");  //发现是根目录，返回根目录
    }
}

//2.从完整的路径中过去filename和parentname
//返回0则为成功，返回-1，则为路径错误
int prasePathName(const char *filepath, char *filename, char *parentname){
    char temp_path[128];
    memcpy(temp_path,filepath,sizeof(temp_path));
    char *tokens[128];
    char *token = NULL;
    char *saveptr = NULL;
    int count = 0;
    token = strtok_r(temp_path,"/",&saveptr);
    while (token != NULL){
        tokens[count] = token;
        token = strtok_r(NULL,"/",&saveptr);
        count = count + 1;
    }
    if (count == 0) return -1; //路径错误

    strncpy(filename,tokens[count -1],256);  //无论count为1还是大于1，最后一个都是filename
    if (count >= 2){
        strncpy(parentname,tokens[count - 2], 256); //当count大于2则倒数第二个是父目录名
    } else {
        strcpy(parentname,"/");  //如果只有一级，那，父目录则是根目录
    }
    return 0;
}

//3.PathInfo的初始化
PathInfo *InitPathInfo(const char *filepath){
    PathInfo *info = (PathInfo *)calloc(1,sizeof(PathInfo));
    if (info == NULL){
        printf("[InitPathInfo] invalid path format:%s\n",filepath);
        return NULL;
    }
        // 特殊处理根目录 "/"
    if (strcmp(filepath, "/") == 0) {
        strcpy(info->parentName, "/");
        strcpy(info->parentPath, "/");
        strcpy(info->fileName, "/");
        return info;
    }

    //调用函数1，获取父目录路径
    getParentPath(filepath,info->parentPath);
    //调用函数2，获取当前目录名称和父目录名称
    int ret = prasePathName(filepath,info->fileName,info->parentName);
    if (ret == -1){
        printf("[InitPathInfo] invalid path format:%s\n",filepath);
        free(info);
        return NULL;
    }
    return info;
}

//4.配套的关闭函数
void freePathInfo(PathInfo *p){
    if (p != NULL) free(p);
}

//涉及VfsRecord相关的函数
//5.初始化VfsRecord结构体，包含路径名，用户名，默认属性，和嵌套的Pathinfo
VfsRecord *initVfsRecord(const char *filepath, const char *username){
    VfsRecord *rec = (VfsRecord *)calloc(1,sizeof(VfsRecord));
    if (rec == NULL){
        printf("[initVfsRecond] malloc fained\n");
        return NULL;
    }
    //先传入路径
    memcpy(rec->path,filepath,sizeof(rec->path));
    //传入名称
    memcpy(rec->userName,username,sizeof(rec->userName));

    //其他类型初始化
    rec->fileId = -1;
    rec->parentId = -1;
    rec->fileType = -1;
    rec->isDeleted = 0;
    rec->refCount = 1;
    memcpy(rec->hashValue,"NULL",sizeof(rec->hashValue));
    rec->pathinfo = InitPathInfo(filepath);
    if (rec->pathinfo == NULL){
        free(rec);
        return NULL;
    }
    return rec;
}

//6.配套清理函数
void freeVfsRecord(VfsRecord *p){
    if (p == NULL) return;
    if (p->pathinfo != NULL) {
        freePathInfo(p->pathinfo);
    }
    free(p);
}

//这里是数据库操作相关函数，可复用
//7.查询父目录id，找不到则返回-1
int queryParentId(MYSQL *db, VfsRecord *p){
    char sql[512];
    int qret;
    //1.分类讨论，当前目录就是根目录
    if (strcmp(p->pathinfo->fileName, "/") == 0) {
        p->parentId = 0;
    //2.当前目录的父目录为根目录
    } else if (strcmp(p->pathinfo->parentName, "/") == 0){
        p->parentId = 1;
    }  else {
    //3.当前目录为多级目录
        snprintf(sql, sizeof(sql),
                "SELECT id FROM vfs WHERE fileName = '%s' AND path = '%s' AND userName = '%s' AND isDeleted = 0",
                p->pathinfo->parentName, p->pathinfo->parentPath, p->userName);
        qret = mysql_query(db, sql);
        MYSQL_CONNECT_CHECK(qret != 0, db, "queryParentId");

        MYSQL_RES *result = mysql_store_result(db);
        MYSQL_CONNECT_CHECK(result == NULL, db, "Store Result");
        MYSQL_ROW row = mysql_fetch_row(result);
        if (row != NULL) {
            p->parentId = atoi(row[0]);
            mysql_free_result(result);
        } else {
            printf("parent not found for parent file %s\n", p->pathinfo->parentName);
            mysql_free_result(result);
            return -1;
        }
    }
    return 0;
}

//8.插入语句的核心逻辑
int insertFile(MYSQL *db, VfsRecord *p){
    char sql[256];
    int qret;
    snprintf(sql, sizeof(sql),
             "INSERT INTO vfs (path, fileName, fileType, parentId, userName, hashValue, isDeleted, refCount) "
             "VALUES ('%s', '%s', %d, %d, '%s', '%s', %d, %d)",
             p->path, p->pathinfo->fileName, p->fileType, p->parentId, p->userName, p->hashValue, p->isDeleted, p->refCount);

    qret = mysql_query(db, sql);
    MYSQL_CONNECT_CHECK(qret != 0, db, "insert");
    printf("insert successfully filename: %s\n", p->pathinfo->fileName);
    return 0;
}

//9.更新父目录的引用计数+1
//如果父目录的id不为0，即不为根目录，则对上一级目录的引用计数+1
int updateParentRef(MYSQL *db, VfsRecord *p){
    if (p->parentId != 0) {
        char sql[256];
        snprintf(sql, sizeof(sql), "UPDATE vfs SET refCount = refCount + 1 WHERE id = %d", p->parentId);
        int qret = mysql_query(db, sql);
        MYSQL_CONNECT_CHECK(qret != 0, db, "updateParentRef");
        
        if (mysql_affected_rows(db) == 0) {  //判断这个语句是不是实际修改了，还是说凭空加了一行
            printf("[updateParentRef] Warning: No parent record updated for parentId = %d\n", p->parentId);
        } else {
            printf("[updateParentRef] Parent refCount +1 for parentId = %d\n", p->parentId);
        }
    }
    return 0;
}


//10.组合排列的插入语句
//创建文件的业务逻辑，包含父目录查找、插入、引用计数更新
int createFile(MYSQL *db, VfsRecord *rec, int filetype, const char *hashvalue) {
    strncpy(rec->hashValue, hashvalue, sizeof(rec->hashValue));
    rec->fileType = filetype;

    if (queryParentId(db, rec) == -1) {
        printf("[create_vfs_file] parent query failed\n");
        return -1;
    }

    if (insertFile(db, rec) != 0) {
        printf("[create_vfs_file] insert failed\n");
        return -1;
    }
    // 如果有父目录，更新父目录引用计数
    updateParentRef(db, rec);
    return 0;
}

//对单个文件的删除语句进行处理
//删除的逻辑是把当前的文件isdelete改为1，且父目录的refcount-1
//11.将isDelete改为1
int updateDetele(MYSQL *db, VfsRecord *p){
        char sql[256];
    int qret;
    snprintf(sql, sizeof(sql),
         "UPDATE vfs SET isDeleted = 1 WHERE fileName = '%s' AND path = '%s' AND userName = '%s' AND isDeleted = 0",
         p->pathinfo->fileName, p->path, p->userName);
    qret = mysql_query(db, sql);
    MYSQL_CONNECT_CHECK(qret != 0, db, "insert");
    printf("Delete successfully filename: %s\n", p->pathinfo->fileName);
    return 0;
}

//12.更新父目录的引用计数
//有一个必然性逻辑，就是只要当前这个文件对应的VfsRecord节点是存在的，那就说明父目录的引用计数必然是大于1的
int deleteParentRef(MYSQL *db, VfsRecord *p){
    //如果父目录的id大于0，且当前的引用计数大于1，则对上一级目录的引用计数-1
    char sql[256];
    int qret;
    if (p->parentId != 0) {
        memset(sql, 0, sizeof(sql));
        snprintf(sql, sizeof(sql), "UPDATE vfs SET refCount = refCount - 1 WHERE id = %d", p->parentId);
        qret = mysql_query(db, sql);
        MYSQL_CONNECT_CHECK(qret != 0, db, "Update Parent RefCount");
        if (mysql_affected_rows(db) == 0) {
        printf("[deleteParentRef] Warning: No parent refCount updated for parentId = %d\n", p->parentId);
        } else {
            ("Parent refCount updated for parentId = %d\n", p->parentId);
        }
    }
    return 0;
}

//13.查询当前VfsRecord节点的refCount的函数
int queryRefCount(MYSQL *db, VfsRecord *p) {
    char sql[512];
    int qret;
    snprintf(sql, sizeof(sql),
             "SELECT refCount FROM vfs WHERE fileName = '%s' AND path = '%s' AND userName = '%s' AND isDeleted = 0",
             p->pathinfo->fileName, p->path, p->userName);

    qret = mysql_query(db, sql);
    MYSQL_CONNECT_CHECK(qret != 0, db, "querySelfRefCount");

    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_CONNECT_CHECK(result == NULL, db, "Store Result (querySelfRefCount)");

    MYSQL_ROW row = mysql_fetch_row(result);
    if (row != NULL) {
        p->refCount = atoi(row[0]);
        mysql_free_result(result);
        return 0;
    } else {
        printf("[querySelfRefCount] record not found for fileName = %s\n", p->pathinfo->fileName);
        mysql_free_result(result);
        return -1;
    }
}

//14.查询当前节点的fileId的函数
int queryFileId(MYSQL *db, VfsRecord *p) {
    char sql[256];
    snprintf(sql, sizeof(sql),
             "SELECT id FROM vfs WHERE fileName = '%s' AND path = '%s' AND userName = '%s' AND isDeleted = 0",
             p->pathinfo->fileName, p->path, p->userName);

    int qret = mysql_query(db, sql);
    MYSQL_CONNECT_CHECK(qret != 0, db, "querySelfFileId");

    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_CONNECT_CHECK(result == NULL, db, "store result (querySelfFileId)");

    MYSQL_ROW row = mysql_fetch_row(result);
    if (row != NULL) {
        p->fileId = atoi(row[0]);
        mysql_free_result(result);
        printf("[querySelfFileId] Found fileId = %d for fileName = %s\n", p->fileId, p->pathinfo->fileName);
        return 0;
    } else {
        printf("[querySelfFileId] No record found for fileName = %s\n", p->pathinfo->fileName);
        mysql_free_result(result);
        return -1;
    }
}



//15.递归删除语句
//如果当前要删除的这个节点引用计数大于1，先递归删除其所有子节点，最后再删除其本体
int deleteRecord(MYSQL *db, VfsRecord *p){
    char sql[256];
    //1.查询当前节点引用计数
    int qret;
    qret = queryRefCount(db,p);
    if (qret == -1){
        printf("[deleteVfsRecordRecursive] Cannot query refCount for %s\n", p->pathinfo->fileName);
        return -1;
    }
    //2.如果当前的引用计数大于1
    if (p->refCount > 1){
        snprintf(sql,sizeof(sql),
                "select path from vfs where parentId = %d and isDeleted = 0",p->fileId);
        
        qret = mysql_query(db,sql);
        MYSQL_CONNECT_CHECK(qret != 0,db,"query children for recursion delete");

        MYSQL_RES *result = mysql_store_result(db);
        MYSQL_CONNECT_CHECK(result == NULL, db, "store result (querySelfFileId)");

        MYSQL_ROW row;
        //递归删除逻辑
        while((row= mysql_fetch_row(result)) != NULL){
            const char *childpath = row[0];
            VfsRecord *child = initVfsRecord(childpath,p->userName);
            if (child == NULL){
                printf("delete recursion failed in this child path:%s\n",childpath);  //不要对空指针解引用
                continue;
            }
            //对每个子节点都找其父节点，其实就是一套初始化的操作
            qret = queryParentId(db,child);
            if (qret == -1){
                printf("[deleterecursion] failed in child path %s\n",child->pathinfo->fileName);
                freeVfsRecord(child);
                continue;
            }

            //对每个子节点都找其当前引用计数
            qret = queryRefCount(db,child);
            if (qret == -1){
                printf("delete recursion failed in this path:%s\n",child->pathinfo->fileName);
                freeVfsRecord(child);
                continue;
            }

            //对每个子节点都找到其当前的fileId
            qret = queryFileId(db,child);
            if (qret == -1){
                printf("delete recursion failed in this path:%s\n",child->pathinfo->fileName);
                freeVfsRecord(child);
                continue;
            }
            //递归删除子节点
            qret = deleteRecord(db,child);
            if (qret == -1){
                printf("delete recursion failed in this path:%s\n",child->pathinfo->fileName);
                freeVfsRecord(child);
                continue;
            }
            //删除子节点之后要清理
            freeVfsRecord(child);
        }
        mysql_free_result(result);
    }
    //3.删除当前这个逻辑节点，更新父引用的计数
    qret = updateDetele(db,p);
    if (qret == 0){
        deleteParentRef(db,p);
        printf("delete final node path:%s\n",p->pathinfo->fileName);
    } else{
        printf("delete failed to delete node path %s\n",p->pathinfo->fileName);
    }
    return 0;
}


//16.查询并打印语句
void queryPrint(MYSQL *db, const char *sql){
    int qret = mysql_query(db, sql);
    MYSQL_QUERY_CHECK(qret != 0, db, "Query");

    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_QUERY_CHECK(result == NULL, db, "Store Result");

    int num_fields = mysql_num_fields(result);
    MYSQL_FIELD *fields = mysql_fetch_fields(result);

    // 打印表头
    for (int i = 0; i < num_fields; i++){
        printf("%s\t", fields[i].name);
    }
    printf("\n");

    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result))){
        for (int i = 0; i < num_fields; i++){
            printf("%s\t", (row[i] != NULL) ? row[i] : "NULL");
        }
        printf("\n");
    }

    mysql_free_result(result);
}

//生成随机hash
void random_hash(char *buf, int len) {
    const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    for (int i = 0; i < len - 1; i++) {
        buf[i] = charset[rand() % (sizeof(charset) - 1)];
    }
    buf[len - 1] = '\0';
}


int main() {
    srand(time(NULL));
    MYSQL *db = mysql_init(NULL);
    MYSQL_CONNECT_CHECK(db == NULL, db, "Init");
    MYSQL *conn = mysql_real_connect(db, "localhost", "root", "654321", "diskStore", 0, NULL, 0);
    MYSQL_CONNECT_CHECK(conn == NULL, db, "Connect");

    const char *username = "zzz";

    //插入逻辑
    // // 根目录
    // VfsRecord *root = initVfsRecord("/", username);
    // if (!root) return -1;
    // createFile(db, root, 0, "NULL");
    // free(root);

    // // 目录 dir1
    // VfsRecord *dir1 = initVfsRecord("/dir1", username);
    // if (!dir1) return -1;
    // createFile(db, dir1, 0, "NULL");
    // free(dir1);

    // // 目录 dir2
    // VfsRecord *dir2 = initVfsRecord("/dir2", username);
    // if (!dir2) return -1;
    // createFile(db, dir2, 0, "NULL");
    // free(dir2);

    // // 文件 /dir1/file1.txt
    // VfsRecord *file1 = initVfsRecord("/dir1/file1.txt", username);
    // if (!file1) return -1;
    // char hash1[65];
    // random_hash(hash1, sizeof(hash1));
    // createFile(db, file1, 1, hash1);
    // free(file1);

    // // 文件 /dir2/file2.txt
    // VfsRecord *file2 = initVfsRecord("/dir2/file2.txt", username);
    // if (!file2) return -1;
    // char hash2[65];
    // random_hash(hash2, sizeof(hash2));
    // createFile(db, file2, 1, hash2);
    // free(file2);

    //查看一下当前的状态
    queryPrint(db, "SELECT * FROM vfs");

    // 初始化根目录
    VfsRecord *root = initVfsRecord("/", username);
    if (!root) return -1;

    // 查找父目录ID、引用计数、fileId，全部更新好
    if (queryParentId(db, root) == -1 || queryRefCount(db, root) == -1 || queryFileId(db, root) == -1) {
        printf("Init failed for root directory, abort delete.\n");
        freeVfsRecord(root);
        mysql_close(db);
        return -1;
    }

    // 开始递归删除
    if (deleteRecord(db, root) == 0) {
        printf("Successfully deleted root and all its children.\n");
    } else {
        printf("Failed to delete root directory.\n");
    }

    freeVfsRecord(root);

    //查看一下当前的状态
    queryPrint(db, "SELECT * FROM vfs");

    mysql_close(db);
    printf("All records inserted successfully.\n");
    return 0;

}






//第一版，没有把函数分块的插入代码
//可用部分第一版
// //辅助函数，找出父目录的绝对路径，从当前的路径里切割出来
// void get_parent_path(const char *fullPath, char *parentPath) {
//     strcpy(parentPath, fullPath);
//     char *lastSlash = strrchr(parentPath, '/');
//     if (lastSlash && lastSlash != parentPath) {
//         *lastSlash = '\0';
//     } else {
//         strcpy(parentPath, "/");  // 如果只有根目录，保留 "/"
//     }
// }

// //用传过来的参数得到倒数第一和倒数第二两个参数
// VfsRecord *recordInit(char *filepath,char *username){  //已知参数是绝对路径
//     VfsRecord *p = (VfsRecord *)calloc(1,sizeof(VfsRecord));
//     if (p == NULL){
//         printf("failure in recondInit");
//         return NULL;
//     }
//     //先传入路径
//     memcpy(p->path,filepath,sizeof(p->path));
//     //传入名称
//     memcpy(p->userName,username,sizeof(p->userName));

//     //其他类型初始化
//     p->fileId = -1;
//     p->parentId = -1;
//     p->fileType = -1;
//     p->isDeleted = 0;
//     p->refCount = 1;
//     memcpy(p->hashValue,"NULL",sizeof(p->hashValue));

//     //单独对根目录进行处理
//     if (strcmp(filepath, "/") == 0) {
//         strcpy(p->fileName, "/");
//         strcpy(p->parentName, "/");
//         p->parentId = 0;
//         return p;
//     } 
//     if (strcmp(filepath, "/") != 0) {
//         get_parent_path(filepath, p->parentPath);
//     } 

//     char temp_path[128];
//     memcpy(temp_path,filepath,sizeof(temp_path));
//     char *tokens[128];
//     char *token = NULL;
//     char *saveptr = NULL;
//     int count = 0;
//     token = strtok_r(temp_path,"/",&saveptr);
//     while (token != NULL){
//         tokens[count] = token;
//         printf("%s\n",tokens[count]);
//         token = strtok_r(NULL,"/",&saveptr);
//         count = count + 1;
//     }
//     if (count >= 2){
//         strcpy(p->parentName,tokens[count - 2]);
//         strcpy(p->fileName,tokens[count - 1]);
//     } else if (count == 1){
//         strcpy(p->parentName,"/");
//         printf("parent name is %s\n",p->parentName);
//         strcpy(p->fileName,tokens[0]);
//         printf("file name is %s\n",p->fileName);
//     } else {
//         printf("invalid path format: %s\n",filepath);
//         free(p);
//         return NULL;
//     }
//     return p;
// }



// //增加语句
// int createFile(MYSQL *db, VfsRecord *p, int filetype,char *hashvalue){
//     //初始化其他的部分
//     memcpy(p->hashValue,hashvalue,sizeof(p->hashValue));
//     p->fileType = filetype;
//     char sql[512];
//     int qret;
//     //单独对根目录进行处理
//     if (strcmp(p->fileName, "/") == 0) {
//         p->parentId = 0;
//     } else if (strcmp(p->parentPath, "/") == 0){
//         p->parentId = 1;
//     }  else {
//         //不是根目录就往下查父目录的id值

//         snprintf(sql, sizeof(sql),
//                 "SELECT id FROM vfs WHERE fileName = '%s' AND path = '%s' AND userName = '%s' AND isDeleted = 0",
//                 p->parentName, p->parentPath, p->userName);
//         qret = mysql_query(db, sql);
//         MYSQL_CONNECT_CHECK(qret != 0, db, "Query");

//         MYSQL_RES *result = mysql_store_result(db);
//         MYSQL_CONNECT_CHECK(result == NULL, db, "Store Result");
//         MYSQL_ROW row = mysql_fetch_row(result);
//         if (row != NULL) {
//             p->parentId = atoi(row[0]);
//             mysql_free_result(result);
//         } else {
//             printf("parent not found for parent file %s\n", p->parentName);
//             mysql_free_result(result);
//             return -1;
//         }
//     }
//     //清空准备开始插入
//     memset(sql, 0, sizeof(sql));
//     snprintf(sql, sizeof(sql),
//              "INSERT INTO vfs (path, fileName, fileType, parentId, userName, hashValue, isDeleted, refCount) "
//              "VALUES ('%s', '%s', %d, %d, '%s', '%s', %d, %d)",
//              p->path, p->fileName, p->fileType, p->parentId, p->userName, p->hashValue, p->isDeleted, p->refCount);

//     qret = mysql_query(db, sql);
//     MYSQL_CONNECT_CHECK(qret != 0, db, "insert");
//     printf("insert successfully filename: %s\n", p->fileName);

//     //如果父目录的id不为0，即不为根目录，则对上一级目录的引用计数+1
//     if (p->parentId != 0) {
//         memset(sql, 0, sizeof(sql));
//         snprintf(sql, sizeof(sql), "UPDATE vfs SET refCount = refCount + 1 WHERE id = %d", p->parentId);
//         qret = mysql_query(db, sql);
//         MYSQL_CONNECT_CHECK(qret != 0, db, "Update Parent RefCount");
//         printf("Parent refCount updated for parentId = %d\n", p->parentId);
//     }
//     return 0;
// }